/******************************************************************************
 * Copyright 2022 The Airos Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include "components/scene_service/scene_service.h"

#include <string>

#include <glog/logging.h>

#include "google/protobuf/text_format.h"
#include "scene/include/glosa.h"
#include "scene/include/hv_in_map.h"
#include "scene/include/msg_verify.h"
#include "scene/include/rlvw.h"

#include "v2xpb-asn-message-frame.pb.h"

namespace air {
namespace net {

int SceneService::Init(const char* param) {
  LOG(INFO) << "init SceneService";
  return 0;
}

void SceneService::Proc(const std::shared_ptr<const air::link::Msg>& msg) {
  ::v2x::scene::MsgVerify msg_verify;
  ::v2x::scene::Glosa glosa;
  ::v2x::scene::Rlvw rlvw;
  std::string type = msg->GetMsgType();
  std::string data = msg->GetData();
  LOG(INFO) << "get message type : " << type;
  auto msg_frame = std::make_shared<::v2xpb::asn::MessageFrame>();
  LOG(INFO) << "receive message frame";
  msg_frame->ParsePartialFromString(data);
  LOG(INFO) << "data parse result : " << msg_frame->DebugString();
  switch (msg_frame->payload_case()) {
    case ::v2xpb::asn::MessageFrame::PayloadCase::kMapFrame:
      LOG(INFO) << "receive map message";
      map_msg_ = std::make_shared<::v2xpb::asn::Map>(msg_frame->mapframe());
      if (msg_verify.VerifyMap(*map_msg_)) {
        LOG(INFO) << "verify map message success";
      } else {
        map_msg_.reset();
        LOG(ERROR) << "verify map message fail";
      }
      if (map_msg_ && bsm_msg_) {
        hv_in_map_.IsHvInMap(*map_msg_, bsm_msg_->pos(), bsm_msg_->heading());
        if (!hv_in_map_.FindNearestLane()) {
          LOG(ERROR) << "bsm msg and map msg is not match";
          map_msg_->Clear();
          bsm_msg_->Clear();
        } else {
          bsm_map_matched_ = true;
          LOG(INFO) << "bsm msg and map msg is matched";
        }
      }
      break;
    case ::v2xpb::asn::MessageFrame::PayloadCase::kBsmFrame:
      LOG(INFO) << "receive bsm message";
      bsm_msg_ = std::make_shared<::v2xpb::asn::Bsm>(msg_frame->bsmframe());
      if (msg_verify.VerifyBsm(*bsm_msg_)) {
        LOG(INFO) << "verify bsm message success";
      } else {
        bsm_msg_.reset();
        LOG(ERROR) << "verify bsm message fail";
      }
      break;
    case ::v2xpb::asn::MessageFrame::PayloadCase::kSpatFrame:
      LOG(INFO) << "receive spat message";
      spat_msg_ = std::make_shared<::v2xpb::asn::Spat>(msg_frame->spatframe());
      if (msg_verify.VerifySpat(*spat_msg_)) {
        LOG(INFO) << "verify spat messgae success";
      } else {
        spat_msg_.reset();
        LOG(ERROR) << "verify spat message fail";
      }
      if (map_msg_ && spat_msg_ && bsm_msg_ && bsm_map_matched_) {
        const auto& node = hv_in_map_.GetMapNode();
        for (int i = 0; i < spat_msg_->intersections_size(); ++i) {
          const auto& intersection = spat_msg_->intersections(i);
          if (node.id().region() == intersection.node_region()) {
            LOG(INFO) << "spat and map have the same region id";
            if (node.id().id() == intersection.node_id()) {
              LOG(INFO) << "spat and map have the same node id";
              LOG(INFO) << "start scene green light optimal speed advisory";
              const auto& lane = hv_in_map_.GetMapLane();
              glosa.IsGlosa(*bsm_msg_, lane, intersection);
              LOG(INFO) << "start scene red light vilation warning";
              rlvw.IsRlvw(*bsm_msg_, lane, intersection);
            } else {
              LOG(ERROR) << "spat and map have different node id";
            }
          } else {
            LOG(ERROR) << "spat and map have different region id";
          }
        }
        bsm_map_matched_ = false;
        bsm_msg_->Clear();
        map_msg_->Clear();
        spat_msg_->Clear();
      }
      break;
    default:
      LOG(ERROR) << "invalid messgae type, ignored";
      break;
  }
}

}  // namespace net
}  // namespace air
